﻿using System;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Windows.Forms;

namespace BpmConnection2Sec
{
    class InfoUser
    {
        private string userName = null;
        private string realmCode = null;
        private string ouFromAd = null;
        private bool isUserAuthenticatedWithSC = false;
        private System.Collections.Generic.Dictionary<string, string> terminals = null;
        private static Logger logger = Logger.getInstance();

        public InfoUser(string userName)
            : base()
        {
            this.userName = userName;
            this.loadUserFromAD();
            logger.log("Getting data of user: " + userName + "@" + System.Environment.MachineName + " realm:[" + this.realmCode + "]...", "STD");
            this.loadFromSecurityServer();
            this._isUserAuthenticatedWithSmartCard();
        }

        public InfoUser() : base(){}

        public InfoUser(string userName, bool onlySmartCardUpdate)
        {
            this.userName = userName;
            this.loadUserFromAD();            
            this._isUserAuthenticatedWithSmartCard();             
        }      

        private void loadUserFromAD(){
            try
            {
                //NEW-VERSION: RECUPERO IL REALM UTILIZZANDO AD
                String ADEntry = System.Environment.GetEnvironmentVariable("USERDNSDOMAIN");
                //Console.WriteLine("AD Entry found: " + ADEntry);
                using (DirectoryEntry de = new DirectoryEntry("LDAP://" + ADEntry))
                {
                    using (DirectorySearcher adSearch = new DirectorySearcher(de))
                    {
                        adSearch.Filter = "(sAMAccountName=" + this.userName + ")";
                        SearchResult adSearchResult = adSearch.FindOne();
                        String sres = adSearchResult.Path;
                        //Console.WriteLine("Path: "+sres);
                        String[] resFields = sres.Split(',');
                        String ou = resFields[1];
                        this.ouFromAd = ou.Split('=')[1];
                        String realmC = resFields[3];
                        String[] realmCF = realmC.Split('=');
                        this.realmCode = realmCF[1].Substring(0, 2);
                    }

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Errore durante l'interrogazione AD: " + ex.Message);
                logger.log("Errore durante l'interrogazione AD", "ERR");
                //System.Windows.Forms.MessageBox.Show("Errore durante l'interrogazione AD. " + ex.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                Environment.ExitCode = 1;
                throw new Exception("Errore durante l'interrogazione AD. " + ex.Message);
            }
        }

        private void loadFromSecurityServer() {
            try
            {
                TerminalWSService.UserInfo userInfo = UserTerminalBD.userInformation(this.userName, this.realmCode);
                if (userInfo != null)
                {
                    String log = "The following data has been retrived:\r\n ";
                    log += "\r\n     User: " + userInfo.userId;
                    log += "\r\n     RealmCode: " + userInfo.realm.code;
                    log += "\r\n     RealmDescription: " + userInfo.realm.description;
                    log += "\r\n     Number of terminals: " + userInfo.terminals.Length + "\r\n";
                    for (int i = 0; i < (int)userInfo.terminals.Length; i++)
                    {
                        log += "        Terminal[" + (i + 1) + "]: " + userInfo.terminals[i].physicalName + "   Type: [" + userInfo.terminals[i].termType.name + "]\r\n ";
                    }
                    logger.log(log, "STD");

                    this.realmCode = userInfo.realm.code;
                    TerminalWSService.Terminal[] terminalArray = userInfo.terminals;
                    terminals = new Dictionary<string, string>();
                    foreach (TerminalWSService.Terminal term in terminalArray)
                    {
                        try
                        {
                            terminals.Add(term.termType.name, term.physicalName);
                        }
                        catch (NullReferenceException nr)
                        {
                            Environment.ExitCode = 1;
                            //System.Windows.Forms.MessageBox.Show("Null Reference Excption. " + nr.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                            logger.log("Null Reference Exception while adding terminal types", "ERR");
                            throw new Exception("Null Reference Exception. " + nr.Message);
                        }
                    }
                }
                else
                {
                    logger.log("No data retrived from TerminalWS", "STD");
                }

            }
            catch (Exception ex)
            {
                String exMes = ex.Message;
                Console.WriteLine("ERROR GETTING USER INFO FROM SERVICE [TERMINALWS]");
                Console.WriteLine("Details:" + exMes);
                logger.log("Error while getting user data: " + exMes, "ERR");
                //System.Windows.Forms.MessageBox.Show("ERROR GETTING USER INFO FROM SERVICE [TERMINALWS]. " + ex.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                Environment.ExitCode = 1;
                throw new Exception("Errore nel recupero delle informazioni sul terminale dell'utente dal server centrale: " + ex.Message);
            }
        
        }
        public bool isUserAuthenticatedWithSmartCard() {
            return this.isUserAuthenticatedWithSC;
        }

        private void _isUserAuthenticatedWithSmartCard()
        {
            X509Store store = null;            
            try
            {
                //vado a prendere il certificato utente.
                /*  Su Windows 7 genera un eccezione */
                store = new X509Store(StoreName.My, StoreLocation.CurrentUser);

                store.Open(OpenFlags.ReadOnly);

                X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
                //cerco il certificato dell'utente loggato
                X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindBySubjectName,this.userName,true);
                X509Certificate2Collection f2collection = (X509Certificate2Collection)fcollection.Find(X509FindType.FindByApplicationPolicy,"Smart Card Logon", true);
                this.isUserAuthenticatedWithSC = (f2collection.Count != 0);
            }
            catch (SystemException se)
            {
                Console.WriteLine("Errore durante l'accesso ai certificati:"+se.Message);
                //System.Windows.Forms.MessageBox.Show("Errore durante l'accesso ai certificati. " + se.Message, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                Environment.ExitCode = 1;
                throw new Exception("Errore durante l'accesso ai certificati. " + se.Message);
            }
            finally
            {
                if (store != null)
                {
                    store.Close();
                }
            }           
        }
        public string getOuFromAd() 
        {
            return this.ouFromAd;
        }
        public string getVideoTerminalCode()
        {
            return getTerminalByType("PRODUCTION_HOST_TERMID");
        }

        public string getPrinterTerminalCode()
        {
            return getTerminalByType("PRODUCTION_LOCAL_PRINTER");
        }

        public string getVideoTerminalCodeForDevelopEnvironment()
        {
            return getTerminalByType("DEVELOPMENT_HOST_TERMID");
        }

        public string getPrinterTerminalCodeForDevelopEnvironment()
        {
            return getTerminalByType("DEVELOPMENT_LOCAL_PRINTER");
        }

        public bool hasDevelopEnvironment()
        {
            if (getVideoTerminalCodeForDevelopEnvironment() == null)
                return false;
            else
                return true;
        }

        private string getTerminalByType(string terminalType)
        {
            string value = null;
            try
            {
                value = terminals[terminalType];
            }
            catch (KeyNotFoundException)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("\nWARNING: tipo di terminale [{0}] non trovato.", terminalType);
                Environment.ExitCode = 1;
                //System.Windows.Forms.MessageBox.Show("Tipo di terminale non trovato: " + terminalType, "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);

            }
            catch (NullReferenceException)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("\nERROR: oggetto InfoUser non ancora inizializzato.");
                //System.Windows.Forms.MessageBox.Show("Oggetto InfoUser non ancora inizializzato: ", "APPLICATION ERROR", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                Environment.ExitCode = 1;
            }
            finally
            {
                Console.ResetColor();
            }
            return value;
        }

        public string getUserName()
        {
            return this.userName;
        }
    }
}
